import re
import warnings
from threading import Lock
from projectConfig import CYCLE_CALLBACK, WEAK_CHECK_CALLBACK
import time
import datetime
class CallBackBuffer:
    def __init__(self, role):
        self.role = role
        self.buf = []
        self.cycle_buf = []
        self.lock = Lock()

    def clear(self):
        self.lock.acquire()
        self.buf.clear()
        self.cycle_buf.clear()
        self.lock.release()

    def store_callback(self, key, value):
        self.lock.acquire()
        if key in CYCLE_CALLBACK:
            self.cycle_buf.append(value)
        else:
            self.buf.append(value)
        self.lock.release()

    def verify_callback(self, expect, timeout=5, **kwargs):
        self.verify_custom_callback(expect, kwargs, timeout)

    def verify_custom_callback(self, expect, kwargs, timeout=5):
        """
        自定义校验字段，需要校验的字段由kwargs传入，可以暴露到用例层面
        """
        start_time = datetime.datetime.now()
        now_time = datetime.datetime.now()
        while (now_time-start_time).seconds < timeout:
            ret = self._verify_callback(expect, kwargs)
            if ret:
                return
            time.sleep(0.2)
            now_time = datetime.datetime.now()
        for key, value in kwargs.items():
            expect += ' ' + str(key) + ':' + str(value)
        assert False, '\n失败设备:%s\n期望callback:%s\n  当前callback:%s' % (self.role, expect, self.to_string())

    def verify_feedback_callback(self, expect, timeout=5, **kwargs):
        start_time = datetime.datetime.now()
        now_time = datetime.datetime.now()
        while (now_time-start_time).seconds < timeout:
            ret = self._verify_callback(expect, kwargs)
            if ret:
                return
            time.sleep(0.2)
            now_time = datetime.datetime.now()
        for key, value in kwargs.items():
            expect += ' ' + str(key) + ':' + str(value)
        warnings.warn('反馈失败设备:%s\n期望callback:%s\n  当前callback:%s' % (self.role, expect, str(self.buf)))

    def _verify_callback(self, expect, kwargs):
        ret = False
        self.lock.acquire()
        if self.is_cycle_callback(expect):
            for i in range(len(self.cycle_buf) - 1, -1, -1):
                if expect in self.cycle_buf[i]:
                    ret = True
                    for key, value in kwargs.items():
                        result = re.findall(key + r'[\s:=]*\w*', self.cycle_buf[i])  # 匹配出对应的字段
                        if len(result) > 0:
                            sep = re.findall(r'[\s:=]', result[0])[0]  # 分隔符
                            if str(value) == result[0].split(sep, 1)[1].strip():
                                field_verify = True
                            else:
                                field_verify = False
                            ret = ret and field_verify  # 只要其中一个字段验证不通过就判断为False
                if ret:
                    break
            if ret:  # 清空已经验证过的周期性回调
                for i in range(len(self.cycle_buf) - 1, -1, -1):
                    if expect in self.cycle_buf[i]:
                        self.cycle_buf.pop(i)
        else:
            for i in range(len(self.buf) - 1, -1, -1):
                if expect in self.buf[i]:
                    self.buf.pop(i)
                    ret = True
                    break
        self.lock.release()
        return ret

    def is_cycle_callback(self,expect_callback):
        for callback in CYCLE_CALLBACK:
            if callback in expect_callback:
                return True
        return False


    # def verify_cycle_callback(self, expect):
    #     ret = False
    #
    #     return ret

    def to_string(self):
        self.lock.acquire()
        string = 'NORMAL CALLBACK:\n'
        for callback in self.buf:
            string = string + callback +'\n'
        string = string + 'CYCLE CALLBACK:\n'
        for callback in self.cycle_buf:
            string = string + callback + '\n'
        self.lock.release()
        return string

    def check_empty(self):
        if len(self.buf) == 0:
            return
        else:
            self.lock.acquire()
            # 弱网多余回调warning
            for i in range(len(self.buf) - 1, -1, -1):
                if self._check_weak_callback(self.buf[i]):
                    warning_callback = self.buf.pop(i)
                    warnings.warn(self.role + ': 弱验证callback: %s' % warning_callback)
            self.lock.release()
            # 过滤弱验证回调后，buffer中剩余的是需要强验证的回调
            if len(self.buf) != 0:
                assert False, '\n\n%s:\n\n期望callback buffer为空\n当前剩余callback:%s' % (self.role, self.to_string())

    def _check_weak_callback(self, callback):
        ret = False
        for weak_callback in WEAK_CHECK_CALLBACK:
            name = weak_callback.split(' ', 1)[0]  # 回调名
            if name in callback:
                res = True
                re_weak = re.findall(r'\w+[:=：]\s*\w*', weak_callback)  # 匹配出弱验证定义中的字段
                if len(re_weak) == 0:  # 弱验证配置回调没有需要具体校验的字段
                    return True
                for field in re_weak:
                    sep = re.findall(r'[:=：]', field)[0]  # 分割符
                    key = field.split(sep)[0].strip()
                    value = field.split(sep)[1].strip()
                    re_callback = re.findall(key + r'[\s:=]*\w*', callback)  # 匹配出回调中的字段
                    if len(re_callback) > 0:
                        sep = re.findall(r'[\s:=]', re_callback[0])[0]  # 分割符
                        res = value == re_callback[0].split(sep, 1)[1].strip() and res
                    else:
                        res = False
                ret = res or ret
        return ret


if __name__ == '__main__':
    # {"type": "error", "key": "yy.com.thunderbolt.manager.MediaManager.initialize",
    #  "value": "java.lang.NoSuchMethodException: yy.com.thunderbolt.manager.MediaManager..initialize []"}
    #
    # {"type": "callback", "key": "onConnectionStatus", "value": "onConnectionStatus: status: 0\n"}
    #
    # {"type": "return", "key": "yy.com.thunderbolt.manager.MediaManager.initialize", "value": "285"}
    callbackbuff = CallBackBuffer()

    callbackbuff.store_callback('onConnectionStatus', 'onConnectionStatus: status: 0')
    callbackbuff.store_callback('onConnectionStatus', 'onConnectionStatus: status: 0')
    callbackbuff.store_callback('onConnectionStatus', 'onConnectionStatus: status: 2')
    callbackbuff.store_callback('onNetworkTypeChanged', 'onNetworkTypeChanged: type: 3')
    print(callbackbuff.to_string())
    print(callbackbuff.verify_callback('onConnectionStatus: status: 0'))
    print(callbackbuff.to_string())